//
// Created by hjie on 23-5-30.
//
#pragma once

#include <cstdint>
#include <string>
#include <cstring>
#include <vector>
#include "loop_event_define.h"
#include "message_attr.h"
#include "write_buffer.h"

enum EmStunMsgType
{
    EmStunMsgUnKnown  = 0x0000,
    EmBindRequest     = 0x0001,
    EmAllocateRequest = 0x0003,
    EmRefreshRequest  = 0x0004,
    EmCreatePermission = 0x0008,
    EmSendIndication   = 0x0016,
    EmDataIndication   = 0x0017,
    EmBindResponse     = 0x0101,
    EmAllocateSuccessResponse = 0x0103,
    EmBindError               = 0x0111,
    EmSharePrivateRequest     = 0x0002,
    EmSharePrivateResponse    = 0x0102,
    EmRefreshRequestResponse  = 0x0104,
    EmCreatePermissionResponse= 0x0108,
    EmSharePrivateError       = 0x0112,
    EmAllocateErrorResponse   = 0x0113,
};

enum ParseStatus
{
    EmUnknownStatus       = 0x00,
    EmDataNotEnoughStatus = 0x01,
    EmParseFinishStatus   = 0x02,
    EmParseFailStatus     = 0x03,
    EmCheckFingerPrintFail= 0x04,
};

class StunMessage
{
public:
    StunMessage();
    ~StunMessage();
    void SetMsgType(EmStunMsgType type);
    ParseStatus ParseStunMessage(UdpBufferPacket * packet, int & use_length);
    ParseStatus ParseStunMessage(const uint8_t * data, int data_length, int & use_length);
    bool ParseBindRequestData(UdpBufferPacket * packet, int & use_length);
    bool ParseAllocateRequest(UdpBufferPacket * packet, int & use_length);
    ParseStatus ParseAttrData(UdpBufferPacket * packet, int & use_length);
    ParseStatus ParseAttrData(const uint8_t * data, int length, int & use_length, struct sockaddr * addr = nullptr, socklen_t * addr_length = nullptr);
    void ComposeStunPacket(WriteBuffer & data);
    EmStunMsgType GetMsgType() { return m_msg_type; }
    std::shared_ptr<MessageAttr> GetAttrById(MessageAttrType type);
    std::string GetTransactionId() { return m_transaction_id; }
    void AddStunAttr(MessageAttr * attr);
    void AddStunAttr(std::shared_ptr<MessageAttr> attr);
    std::string ProducerTransactionId();
    uint16_t GetAttrLength();
private:
    bool ParseStunHeader(const uint8_t * data, int length);
public:
    EmStunMsgType m_msg_type;
    uint16_t m_data_length;
    uint32_t m_magic_cookie;
    std::string m_transaction_id;
    std::map<MessageAttrType, std::shared_ptr<MessageAttr>> m_attr_map;
private:
    uint16_t m_remote_port;
    uint32_t m_remote_addr;
};

